// copyright:no copyright,use it if you like
// license boilerplate:BSD 3-Clause
// filename:Function.hpp
// author:Tempest(https://gitee.com/Tempest56890)
// date:2023-03-31
// brief:implement the Function BaseClass.

#ifndef __TEMPEST_FUNCTION__
#define __TEMPEST_FUNCTION__

#include <iostream>
#include <cmath>
#include <limits>
#include <stdlib.h>

const double _eps=std::numeric_limits<double>::epsilon();

// implement the funciton of BaseClass.
// implements derivative functions.
// example:
//    (Temporarily omitted.)

class Function_one_dim {
public:
    // Defines a virtual function operator().
    virtual double operator()(const double &x) const =0;
    virtual double First_Order_diff_x(const double &x) const {
        return ((*this)(x+100*_eps)-(*this)(x-100*_eps))/(_eps*200);
    }
    virtual double Second_Order_diff_x(const double &x,const double &y) const {
        double left_diff=((*this)(x)-(*this)(x-200*_eps))/(_eps*200);
        double right_diff=((*this)(x+200*_eps)-(*this)(x))/(_eps*200);
        return (right_diff-left_diff)/(_eps*200);
    }
};

class Function_two_dim {
public:
    // Defines a virtual function operator().
    virtual double operator()(const double &x,const double &y) const =0;
    virtual double First_Order_diff_x(const double &x,const double &y) const {
        return ((*this)(x+100*_eps,y)-(*this)(x-100*_eps,y))/(_eps*200);
    }
    virtual double Second_Order_diff_x(const double &x,const double &y) const {
        double left_diff=((*this)(x,y)-(*this)(x-200*_eps,y))/(_eps*200);
        double right_diff=((*this)(x+200*_eps,y)-(*this)(x,y))/(_eps*200);
        return (right_diff-left_diff)/(_eps*200);
    }
    virtual double First_Order_diff_y(const double &x,const double &y) const {
        return ((*this)(x,y+100*_eps)-(*this)(x,y-100*_eps))/(_eps*200);
    }
    virtual double Second_Order_diff_y(const double &x,const double &y) const {
        double left_diff=((*this)(x,y)-(*this)(x,y-200*_eps))/(_eps*200);
        double right_diff=((*this)(x,y+200*_eps)-(*this)(x,y))/(_eps*200);
        return (right_diff-left_diff)/(_eps*200);
    }
    virtual double diff_xy(const double &x,const double &y) const {
        double diff1=((*this)(x+100*_eps,y-100*_eps)-(*this)(x-100*_eps,y-100*_eps))/(_eps*200);
        double diff2=((*this)(x+100*_eps,y+100*_eps)-(*this)(x-100*_eps,y+100*_eps))/(_eps*200);
        return (diff2-diff1)/(_eps*200);
    }
};

#else
#endif
